import { defineStore } from "pinia";
import { computed, ref } from "vue";
import chatService from "@/services/chatService";
import ErrorHandler from "@/utils/errorHandler";
import type { Message } from "@/types";

type MessageMap = Record<string, Message[]>;

const createMessageId = () => {
  if (
    typeof crypto !== "undefined" &&
    typeof crypto.randomUUID === "function"
  ) {
    return crypto.randomUUID();
  }
  return `msg_${Date.now()}_${Math.random().toString(16).slice(2)}`;
};

const normalizeHistoryMessages = (items: any[] = []): Message[] => {
  return items.map((raw) => {
    const metadata =
      typeof raw.metadata === "string"
        ? safeJsonParse(raw.metadata)
        : raw.metadata || {};
    const ragContext =
      raw.rag_context || raw.ragContext || metadata?.rag_context || [];
    return {
      id: raw.id || raw.message_id || createMessageId(),
      role:
        raw.role === "assistant"
          ? "assistant"
          : raw.role === "system"
          ? "system"
          : "user",
      content: raw.content ?? "",
      timestamp: raw.created_at || raw.timestamp || new Date().toISOString(),
      metadata,
      ragContext,
    };
  });
};

const safeJsonParse = (value: string) => {
  try {
    return JSON.parse(value) || {};
  } catch {
    return {};
  }
};

export const useChatStore = defineStore("chat", () => {
  const messagesBySession = ref<MessageMap>({});
  const historyLoadingMap = ref<Record<string, boolean>>({});
  const currentSessionId = ref<string>("");
  const inputMessage = ref("");
  const isSending = ref(false);
  const isStreaming = ref(false);
  const error = ref<string | null>(null);
  const currentModel = ref("llama3.1:8b");
  const streamAbortController = ref<AbortController | null>(null);
  const streamingMessageId = ref<string | null>(null);
  const streamingSessionId = ref<string | null>(null);

  const ensureSessionEntry = (sessionId: string) => {
    if (!messagesBySession.value[sessionId]) {
      messagesBySession.value[sessionId] = [];
    }
  };

  const messages = computed<Message[]>(() => {
    if (!currentSessionId.value) return [];
    return messagesBySession.value[currentSessionId.value] ?? [];
  });

  const hasMessages = computed(() => messages.value.length > 0);
  const isBotTyping = computed(() => isStreaming.value);
  const isHistoryLoading = computed(() => {
    const activeId = currentSessionId.value;
    return Boolean(activeId && historyLoadingMap.value[activeId]);
  });

  const setActiveSession = (
    sessionId: string,
    options: { resetMessages?: boolean } = {}
  ) => {
    if (!sessionId) {
      currentSessionId.value = "";
      return;
    }
    currentSessionId.value = sessionId;
    if (options.resetMessages) {
      messagesBySession.value = { ...messagesBySession.value, [sessionId]: [] };
    } else {
      ensureSessionEntry(sessionId);
    }
  };

  const setCurrentModel = (model: string) => {
    currentModel.value = model;
  };

  const setInputMessage = (value: string) => {
    inputMessage.value = value;
  };

  const setError = (message: string | null) => {
    error.value = message;
  };

  const setHistoryLoading = (sessionId: string, loading: boolean) => {
    historyLoadingMap.value = {
      ...historyLoadingMap.value,
      [sessionId]: loading,
    };
  };

  const replaceMessages = (sessionId: string, nextMessages: Message[]) => {
    messagesBySession.value = {
      ...messagesBySession.value,
      [sessionId]: nextMessages,
    };
  };

  const appendMessage = (sessionId: string, message: Message) => {
    ensureSessionEntry(sessionId);
    const next = [...messagesBySession.value[sessionId], message];
    replaceMessages(sessionId, next);
  };

  const updateMessage = (
    sessionId: string,
    messageId: string,
    patch: Partial<Message>
  ) => {
    const existing = messagesBySession.value[sessionId];
    if (!existing) return;
    const index = existing.findIndex((msg) => msg.id === messageId);
    if (index === -1) return;
    const updated = { ...existing[index], ...patch };
    if (patch.metadata) {
      updated.metadata = {
        ...(existing[index].metadata || {}),
        ...patch.metadata,
      };
    }
    const next = existing.slice();
    next.splice(index, 1, updated);
    replaceMessages(sessionId, next);
  };

  const loadHistoryMessages = async (
    sessionId: string,
    options: { force?: boolean; title?: string } = {}
  ) => {
    if (!sessionId) return;
    if (
      !options.force &&
      (messagesBySession.value[sessionId]?.length ||
        historyLoadingMap.value[sessionId])
    ) {
      return;
    }
    setHistoryLoading(sessionId, true);
    try {
      const { items } = await chatService.getChatHistory(
        sessionId,
        {
          limit: 200,
        },
        { title: options.title }
      );
      replaceMessages(sessionId, normalizeHistoryMessages(items || []));
    } catch (err) {
      ErrorHandler.handleError(err, "加载聊天历史", "auto");
      setError("无法加载历史消息");
    } finally {
      setHistoryLoading(sessionId, false);
    }
  };

  const buildPayloadMessages = (sessionId: string) => {
    const sessionMessages = messagesBySession.value[sessionId] ?? [];
    return sessionMessages
      .filter((msg) => msg.content && msg.content.trim().length > 0)
      .map((msg) => ({
        role: msg.role,
        content: msg.content,
      }));
  };

  const finalizeStreamingState = (
    opts: { sessionId?: string; content?: string; errored?: boolean } = {}
  ) => {
    const targetSession =
      opts.sessionId || streamingSessionId.value || currentSessionId.value;
    if (targetSession && streamingMessageId.value) {
      updateMessage(targetSession, streamingMessageId.value, {
        content: opts.content ?? "",
        metadata: {
          ...(messagesBySession.value[targetSession]?.find(
            (msg) => msg.id === streamingMessageId.value
          )?.metadata ?? {}),
          streaming: false,
          pending: false,
          errored: opts.errored ?? false,
        },
      });
    }
    streamingMessageId.value = null;
    streamingSessionId.value = null;
    streamAbortController.value = null;
    isStreaming.value = false;
    isSending.value = false;
  };

  const sendMessage = async (modelName?: string) => {
    const sessionId = currentSessionId.value;
    const content = inputMessage.value.trim();
    if (!sessionId || !content || isSending.value) {
      return;
    }

    const userMessage: Message = {
      id: createMessageId(),
      role: "user",
      content,
      timestamp: new Date().toISOString(),
      metadata: {},
      ragContext: [],
    };

    appendMessage(sessionId, userMessage);
    inputMessage.value = "";
    error.value = null;
    isSending.value = true;
    isStreaming.value = true;

    const assistantMessageId = createMessageId();
    streamingMessageId.value = assistantMessageId;
    streamingSessionId.value = sessionId;

    appendMessage(sessionId, {
      id: assistantMessageId,
      role: "assistant",
      content: "思考中…",
      timestamp: new Date().toISOString(),
      metadata: { streaming: true, pending: true },
      ragContext: [],
    });

    return new Promise<void>((resolve, reject) => {
      const controller = chatService.sendMessageWithCallbacks(
        {
          sessionId,
          content,
          messages: buildPayloadMessages(sessionId),
          chatConfig: modelName ? { model: modelName } : undefined,
          stream: true,
          assistantId: assistantMessageId,
        },
        {
          onChunk: (_assistantId, fullContent) => {
            const targetSession = streamingSessionId.value || sessionId;
            const targetMessageId = streamingMessageId.value || _assistantId;
            if (!targetSession || !targetMessageId) return;
            updateMessage(targetSession, targetMessageId, {
              content: fullContent || "思考中…",
              metadata: { streaming: true, pending: false },
            });
          },
          onComplete: (_assistantId, fullContent) => {
            finalizeStreamingState({
              sessionId,
              content: fullContent,
              errored: false,
            });
            loadHistoryMessages(sessionId, { force: true }).catch(() => {});
            resolve();
          },
          onError: (_assistantId, err: Error) => {
            const targetSession = streamingSessionId.value || sessionId;
            const targetMessageId = streamingMessageId.value || _assistantId;
            const currentContent =
              targetSession && targetMessageId
                ? messagesBySession.value[targetSession]?.find(
                    (msg) => msg.id === targetMessageId
                  )?.content ?? ""
                : "";
            if (err.name === "AbortError") {
              finalizeStreamingState({
                sessionId,
                content: currentContent,
                errored: false,
              });
              loadHistoryMessages(sessionId, { force: true }).catch(() => {});
              resolve();
              return;
            }
            ErrorHandler.handleError(err, "发送消息", "sse");
            finalizeStreamingState({
              sessionId,
              content: err.message || currentContent,
              errored: true,
            });
            loadHistoryMessages(sessionId, { force: true }).catch(() => {});
            setError(err.message);
            reject(err);
          },
          onWarning: (message: string) => {
            ErrorHandler.showWarning(message, "聊天");
          },
        }
      );
      streamAbortController.value = controller;
    });
  };

  const stopStreaming = () => {
    if (!isStreaming.value || !streamAbortController.value) {
      return;
    }
    streamAbortController.value.abort();
    const targetSession = streamingSessionId.value || currentSessionId.value;
    if (targetSession && streamingMessageId.value) {
      const existing = messagesBySession.value[targetSession]?.find(
        (msg) => msg.id === streamingMessageId.value
      );
      finalizeStreamingState({
        sessionId: targetSession,
        content: existing?.content ?? "",
        errored: false,
      });
      if (targetSession) {
        loadHistoryMessages(targetSession, { force: true }).catch(() => {});
      }
    } else {
      finalizeStreamingState();
    }
  };

  const clearMessages = (sessionId?: string) => {
    if (!sessionId) {
      if (currentSessionId.value) {
        replaceMessages(currentSessionId.value, []);
      }
      return;
    }
    replaceMessages(sessionId, []);
  };

  const addMessage = (sessionId: string, message: Message) => {
    if (!sessionId) return;
    appendMessage(sessionId, message);
  };

  return {
    messages,
    hasMessages,
    isBotTyping,
    isHistoryLoading,
    inputMessage,
    isSending,
    isStreaming,
    error,
    currentModel,
    currentSessionId,
    streamAbortController,

    setActiveSession,
    setCurrentModel,
    setInputMessage,
    setError,
    loadHistoryMessages,
    sendMessage,
    stopStreaming,
    clearMessages,
    addMessage,
  };
});
